package com.jpro.module.infra.controller.admin.file.image;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import org.springframework.lang.Nullable;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Random;

public class ImageUtil {
    /**
     * 1左上 2上 3右上 4左 5中 6右 7左下 8下 9右下
     */
    public static final int POS_LEFT_TOP = 1;
    public static final int POS_TOP = 2;
    public static final int POS_RIGHT_TOP = 3;
    public static final int POS_LEFT = 4;
    public static final int POS_CENTER = 5;

    public static final int POS_RIGHT = 6;
    public static final int POS_LEFT_BOTTOM = 7;
    public static final int POS_BOTTOM = 8;
    public static final int POS_RIGHT_BOTTOM = 9;

    /**
     * 裁剪图片
     *
     * @param src    原图片 本地磁盘绝对路径
     * @param dest   目标图片 本地磁盘绝对路径
     * @param x      x坐标
     * @param y      y坐标
     * @param width  宽度
     * @param height 高度
     * @return 是否操作图片
     */
    public static void cut(String src, String dest, int x, int y, int width, int height) {
        ImgUtil.cut(FileUtil.file(src), FileUtil.file(dest), new Rectangle(x, y, width, height)//裁剪的矩形区域
        );
    }

    /**
     * 缩小图片  缩放图像（按长宽缩放）
     *
     * @param src    原图片。
     * @param dest   目标图片。
     * @param width  图片最大宽度。小于等于 0 则不限制。
     * @param height 图片最大高度。小于等于 0 则不限制。
     * @return 是否操作图片
     */
    public static void resize(String src, String dest, int width, int height) {
        Image scaleImage = ImgUtil.scale(ImgUtil.read(FileUtil.file(src)), width, height);
        ImgUtil.write(scaleImage, FileUtil.file(dest));
    }


    /**
     * 缩放图像（按比例缩放）
     *
     * @param src   源图像文件
     * @param dest  缩放后的图像文件
     * @param scale scale – 缩放比例。比例大于1时为放大，小于1大于0为缩小
     */
    public static void scale(String src, String dest, float scale) {
        ImgUtil.scale(FileUtil.file(src), FileUtil.file(dest), scale);
    }


    /**
     * 文字水印
     *
     * @param src                原图片。
     * @param dest               目标图片(只能是不存在的文件目录)。
     * @param waterTxt           水印文字。
     * @param watermarkTxtColour 文字颜色。
     * @param watermarkTxtSize   文字大小。
     * @param position           水印位置。1左上 2上 3右上 4左 5中 6右 7左下 8下 9右下
     * @param transparency       透明度。0-100。0: 完全透明; 100: 完全不透明。
     * @return 是否操作图片
     */
    public static void pressText(String src, String dest, String waterTxt, String watermarkTxtColour, int watermarkTxtSize, int position, int transparency) {
        File srcFile = FileUtil.file(src);
        BufferedImage imgBuff = ImgUtil.read(srcFile);
        Color color = Color.getColor(watermarkTxtColour);
        Font font = new Font("黑体", Font.PLAIN, watermarkTxtSize);
        Graphics2D g = imgBuff.createGraphics();
        g.setColor(color);
        g.setFont(font);
        AlphaComposite a = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, (float) transparency / 100f);
        g.setComposite(a);
        java.awt.FontMetrics fm = g.getFontMetrics();
        int textHeight = fm.getHeight(); // 计算字体高度
        int textWidth = fm.stringWidth(waterTxt);// 计算字体宽度
        int width = imgBuff.getWidth();
        int height = imgBuff.getHeight();
        Position p = markPosition(width, height, position, textWidth, textHeight);
        ImgUtil.pressText(srcFile, FileUtil.file(dest), waterTxt, //水印文字
                color, font,
                p.x, //x坐标修正值。 默认在中间，偏移量相对于中间偏移
                p.y, //y坐标修正值。 默认在中间，偏移量相对于中间偏移
                transparency / 100f);
    }

    /**
     * 图片水印
     *
     * @param src          原图片。
     * @param dest         目标图片。
     * @param waterImg     水印图片。
     * @param position     水印位置。1左上 2上 3右上 4左 5中 6右 7左下 8下 9右下
     * @param transparency 透明度。0-100。0: 完全透明; 100: 完全不透明。
     * @return 是否操作图片
     */
    public static void watermark(String src, String dest, String waterImg, int position, int transparency) {
        BufferedImage markImgBuff = ImgUtil.read(FileUtil.file(waterImg));
        BufferedImage imgBuff = ImgUtil.read(FileUtil.file(src));
        int width = imgBuff.getWidth();
        int height = imgBuff.getHeight();
        Position p = markPosition(width, height, position, markImgBuff.getWidth(), markImgBuff.getHeight());
        ImgUtil.pressImage(FileUtil.file(src), FileUtil.file(dest), ImgUtil.read(FileUtil.file(waterImg)), //水印图片
                p.x, //x坐标修正值。 默认在中间，偏移量相对于中间偏移
                p.y, //y坐标修正值。 默认在中间，偏移量相对于中间偏移
                transparency / 100f);
    }

    /**
     * 获得水印位置
     *
     * @param width      原图宽度
     * @param height     原图高度
     * @param markWidth  水印宽度
     * @param markHeight 水印高度
     * @param p          水印位置  1左上 2上 3右上 4左 5中 6右 7左下 8下 9右下 其他随机
     * @return 水印位置
     */
    private static Position markPosition(int width, int height, int p, int markWidth, int markHeight) {
        if (p < POS_LEFT_TOP || p > POS_RIGHT_BOTTOM) {
            Random ram = RandomUtil.getRandom(true);
            p = (int) (ram.nextFloat() * 5) + 1;
        }
        int x;
        int y;
        int offsetx = 0;
        int offsety = 0;
        /** 1左上 2上 3右上 4左 5中 6右 7左下 8下 9右下 */
        switch (p) {
            // 左上
            case 1:
                x = -(width - markWidth) / 2;
                y = -(height - markWidth) / 2;
                break;
            // 上中
            case 2:
                x = offsetx;
                y = -(height - markHeight) / 2;
                break;
            // 右上
            case 3:
                x = (width - markWidth) / 2;
                y = -(height - markHeight) / 2;
                break;
            // 左中
            case 4:
                x = -(width - markWidth) / 2;
                y = offsety;
                break;
            // 中
            case 5:
                x = offsetx;
                y = offsety;
                break;
            // 右中
            case 6:
                x = (width - markWidth) / 2;
                y = offsety;
                break;
            // 左下
            case 7:
                x = -(width - markWidth) / 2;
                y = (height - markHeight) / 2;
                break;
            // 下
            case 8:
                x = offsetx;
                y = (height - markHeight) / 2;
                break;
            // 右下
            case 9:
                x = (width - markWidth) / 2;
                y = (height - markHeight) / 2;
                break;
            default:
                throw new RuntimeException("never reach ...");
        }
        return new Position(x, y);
    }

    /**
     * 水印位置包含左边偏移量，右边偏移量。
     */
    public static class Position {
        private int x;
        private int y;

        public Position(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }
    }

    /**
     * 通过 ContextType 获取图片后缀名
     *
     * @param contentType Http响应的MIME type
     * @return 图片后缀名
     */
    @Nullable
    public static String getImageExtension(String contentType) {
        switch (contentType) {
            case "image/jpeg":
                return "jpg";
            case "image/gif":
                return "gif";
            case "image/png":
                return "png";
            case "image/bmp":
                return "bmp";
            case "image/webp":
                return "webp";
            default:
                return null;
        }
    }

}
